

import EventHandler from "./EventHandler.ts"
import {
  KeyBoardEventInfo, MessageEventMap,
  PointerEventInfo, Settings, WheelEventInfo
} from "./types.ts"

function getPointerEventInfo(e: PointerEvent): PointerEventInfo {
  const { pointerType,
    pointerId, ctrlKey,
    shiftKey, altKey, metaKey,
    offsetX, offsetY, type,
    button, } = e
  const pointerEventInfo = {
    pointerType,
    pointerId, ctrlKey,
    shiftKey, altKey, metaKey,
    offsetX, offsetY, type,
    button,
  }
  return pointerEventInfo
}
function getMouseWheelEventInfo(params: WheelEvent): WheelEventInfo {
  const {
    ctrlKey,
    shiftKey,
    altKey,
    metaKey,
    offsetX,
    offsetY,
    type,
    deltaY,
    deltaMode,
  } = params
  const wheelInfo: WheelEventInfo = {
    ctrlKey,
    shiftKey,
    altKey,
    metaKey,
    offsetX,
    offsetY,
    type,
    deltaY,
    deltaMode,
  }
  return wheelInfo
}

function getKeyboardEventInfo(params: KeyboardEvent): KeyBoardEventInfo {
  const {
    ctrlKey,
    shiftKey,
    altKey,
    metaKey,
    type,
    key,
    code,
    repeat,
  } = params
  const info: KeyBoardEventInfo = {
    ctrlKey,
    shiftKey,
    altKey,
    metaKey,
    type,
    key,
    code,
    repeat,
  }
  return info
}
/**
 * 主要用于类型提示的类
 */
class RenderWorker<T extends MessageEventMap = MessageEventMap> {
  #worker?: Worker
  #eventHandler = EventHandler
  get worker() {
    return this.enbleWorker ? this.#worker : this.#eventHandler
  }
  /**
   * 是否其启用worker渲染模式
   * @param enbleWorker 
   */
  constructor(public enbleWorker: boolean = false) {
    if (enbleWorker) {
      this.#worker = new Worker(new URL('../core/WebWorker.ts', import.meta.url), { type: 'module' })
      this.#worker.addEventListener('message', this.workerOnMessage)
      this.#worker.addEventListener('error', (e) => {
        alert(e.message)
      })
      console.log(this.#worker);

    }
  }
  postMessage<K extends keyof MessageEventMap>(type: K, data: T[K], transfer?: Transferable[]): void {

    if (this.#worker) {

      if (transfer) {
        this.#worker.postMessage({ [type]: data }, transfer)
      } else {
        this.#worker.postMessage({ [type]: data })
      }
    } else {
      this.#eventHandler[type](data)
    }
  }
  workerOnMessage = (e: MessageEvent) => {
    alert(JSON.stringify(e.data))
  }
}
/**
 * 当前环境是否支持离屏渲染
 * @returns 
 */
export function OffScreenCanvasSupport() {
  const canvasEle = document.createElement('canvas')
  try {
    const offscreenCanvas = canvasEle.transferControlToOffscreen()
      , ctx = offscreenCanvas.getContext('webgl2')
    if (ctx) {

      return true
    }
  } catch (e) {
    console.error(e);
    return false
  }
}
export class EventInteractor extends EventTarget {
  #resizeTimeoutId: number = 0
  renderWorker: RenderWorker
  #setting = new Settings()
  constructor() {
    super()
    this.renderWorker = new RenderWorker(/* OffScreenCanvasSupport() */)
  }
  initRender(offscreen: OffscreenCanvas, setting: Settings = new Settings()) {
    this.renderWorker.postMessage('init', {
      canvas: offscreen,
      setting
    }, [offscreen])
  }
  pointer = (e: PointerEvent) => {
    this.renderWorker.postMessage('pointer', getPointerEventInfo(e))
  }

  resize(width: number, height: number) {
    if (this.#resizeTimeoutId) {
      clearTimeout(this.#resizeTimeoutId)
    }
    this.#resizeTimeoutId = window.setTimeout(() => {
      this.#resizeTimeoutId = 0
      this.renderWorker.postMessage('resize', {
        width,
        height
      })
    }, 200)
  }

  wheel = (e: WheelEvent) => {
    this.renderWorker.postMessage('wheel', getMouseWheelEventInfo(e))
  }
  keyboard = (e: KeyboardEvent) => {
    this.renderWorker.postMessage('keyboard', getKeyboardEventInfo(e))
  }

  addModel = (modelUrl: string) => {
    const urlset = new Set(this.#setting.models.urls)
    urlset.add(modelUrl)
    this.#setting.models.urls = Array.from(urlset.values())
    this.renderWorker.postMessage('setting', this.#setting)
  }

  deleteModel = (modelUrl: string) => {
    const urlset = new Set(this.#setting.models.urls)
    const deleted = urlset.delete(modelUrl)
    // 不存在的url啥都不做
    if (!deleted) { return }
    this.#setting.models.urls = Array.from(urlset.values())
    this.renderWorker.postMessage('setting', this.#setting)
  }

}